/*
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.testgal.client.impl;

import com.google.gwt.testgal.client.impl.PageMap;
import com.google.gwt.testgal.client.impl.Section;
import com.google.gwt.testgal.client.impl.TestMethod;
import com.google.gwt.testgal.client.impl.TestStatus;
import com.google.gwt.testgal.client.impl.TestSuite;
import com.google.gwt.testgal.client.impl.GalleryRunner;
import com.google.gwt.testgal.client.testing.FakePageHistory;
import com.google.gwt.testgal.client.impl.util.PageHistory;
import com.google.gwt.testgal.client.impl.util.YieldingCommand;
import com.google.gwt.testgal.client.impl.util.Scheduler;
import com.google.gwt.testgal.client.testing.TestGalTestCase;
import com.google.gwt.testgal.client.AbstractTestGallery;

import junit.framework.Assert;
import junit.framework.TestCase;

import java.util.List;

/**
 * Verifies that we report useful errors for misuse of
 * {@link com.google.gwt.testgal.client.AbstractTestGallery}.
 *
 * @author Brian Slesinsky
 */
public class GalleryRunnerTest extends TestGalTestCase {

  private PageMap pages;
  private PageHistory history;

  @Override
  protected void gwtSetUp() throws Exception {
    super.gwtSetUp();
    pages = new PageMap();
    history = new FakePageHistory();
  }

  public void testErrorForPassingNullToAddTests() throws Exception {
    
    TestSuite suite = GalleryRunner.makeTestSuite(new FakeGallery(null), pages, history);
    checkOneTestMethod(suite, "Invalid Section", "(generated by test runner)");
    runTests(suite, 10);

    Section section = getOnlySection(suite);
    TestMethod method = getOnlyTestMethod(suite);

    out.snapshot(pages.getSectionResultPage(section),
        "The section result page for a gallery that calls addSection(null)");
    out.snapshot(pages.getMethodResultPage(section, method),
        "The method result page for a gallery that calls addSection(null)");
    assertSame(TestStatus.FAILED, section.getStatus(method));
  }

  public void testErrorForMissingCallToGWTCreate() throws Exception {

    TestSuite suite = GalleryRunner.makeTestSuite(new FakeGallery(FakeTest.class), pages, history);
    checkOneTestMethod(suite, FakeTest.class.getName(), "(generated by test runner)");
    runTests(suite, 10);

    Section section = getOnlySection(suite);
    TestMethod method = getOnlyTestMethod(suite);

    out.snapshot(pages.getSectionResultPage(section),
        "The section result page for a gallery that doesn't call GWT.create()");
    out.snapshot(pages.getMethodResultPage(section, method),
        "The method result page for a gallery that doesn't call GWT.create()");
    assertSame(TestStatus.FAILED, section.getStatus(method));
  }

  // ======== end of tests ========

  private static void runTests(TestSuite suite, int maxSteps) {
    YieldingCommand command = suite.getRunAllTestsCommand();

    Scheduler scheduler = new Scheduler();
    scheduler.push(command);

    int stepCount = 1;
    while (scheduler.runStepsManually()) {
      stepCount++;
      if (stepCount > maxSteps) {
        fail("stopped command early because it took more than " + maxSteps + " steps to run");
      }
    }
  }

  private static void checkOneTestMethod(TestSuite suite, String expectedSectionName,
      String expectedMethodName) {
    assertEquals(1, suite.getTestMethodCount());
    assertEquals(expectedSectionName, getOnlySection(suite).getName());
    assertEquals(expectedMethodName, getOnlyTestMethod(suite).getName());
  }

  private static Section getOnlySection(TestSuite suite) {
    List<Section> sections = suite.getSections();
    Assert.assertEquals(1, sections.size());
    return sections.get(0);
  }

  private static TestMethod getOnlyTestMethod(TestSuite suite) {
    List<TestMethod> methods = getOnlySection(suite).getMethods();
    Assert.assertEquals(1, methods.size());
    return methods.get(0);
  }

  private class FakeGallery extends AbstractTestGallery {

    private final Object addTestsArgument;

    public FakeGallery(Object addTestsArgument) {
      this.addTestsArgument = addTestsArgument;
    }

    protected void defineGallery() {
      addSection(addTestsArgument, null);
    }
  }

  private static class FakeTest extends TestCase {
    public void testSomething() throws Exception {
    }
  }
}
